package user

import (
	"HeadLineNews/pkg/db/store"
	"HeadLineNews/pkg/snow"
	"HeadLineNews/pkg/zaplog"
	models "HeadLineNews/proto_models/app/account_model"
	"HeadLineNews/resp"
	"HeadLineNews/utils/transaction"
	"database/sql"
	"errors"
	"github.com/gin-gonic/gin"
	"github.com/jmoiron/sqlx"
)

var (
	errUserHasExists = errors.New("当前用户已存在")
	errUserNotExists = errors.New("用户名或密码错误")
)

type Repo interface {
	CheckUniqueUserName(c *gin.Context, userName string) (err error)
	InsertUser(c *gin.Context, p *models.RequestUserRegister) (userId, token string, err error)

	CheckLoginData(c *gin.Context, p *models.RequestUserLogin) (np *models.RequestUserLogin, err error)
}

type repo struct {
	db *sqlx.DB
}

func NewRepo() Repo {
	return &repo{db: store.DB()}
}

// CheckUniqueUserName 注册检查唯一用户名
func (r *repo) CheckUniqueUserName(c *gin.Context, userName string) (err error) {
	sqlStr := `SELECT COUNT(*) FROM app__account WHERE user_name=?`
	var count int64
	if err = r.db.Get(&count, sqlStr, userName); err != nil {
		zaplog.L().Error("query user count by userName failed", zaplog.Fields(c, userName, err)...)
		resp.ServerBusy(c)
		return
	}
	if count > 0 {
		err = errUserHasExists
		zaplog.L().Warn("user has exists", zaplog.Fields(c, userName, nil)...)
		resp.UnprovedParam(c, err.Error())
		return
	}
	return
}

// InsertUser 将用户保存进数据库
func (r *repo) InsertUser(c *gin.Context, p *models.RequestUserRegister) (userId, token string, err error) {
	if err = transaction.Transaction(r.db, func(tx *sqlx.Tx) (te error) {
		// 将用户保存进数据库
		sqlStr := `INSERT INTO app__account(
            user_id, user_name, user_pwd, create_time, last_update_time, last_login_time) 
			VALUES (?,?,?,NOW(),NOW(),NOW())`
		userId = snow.GetID()
		if _, te = tx.Exec(sqlStr, userId, p.UserName, p.UserPwd); te != nil {
			zaplog.L().Error("insert user failed", zaplog.Fields(c, p, te)...)
			return
		}
		// 签发 token
		if token, te = NewCache().RegUserRegisterToken(c, userId); te != nil {
			zaplog.L().Error("reg user register token failed", zaplog.Fields(c, userId, te)...)
			return
		}
		return
	}); err != nil {
		resp.ServerBusy(c)
		return
	}
	return
}

// CheckLoginData 检查 user 登录数据
func (r *repo) CheckLoginData(c *gin.Context, p *models.RequestUserLogin) (np *models.RequestUserLogin, err error) {
	sqlStr := `SELECT user_id FROM app__account WHERE user_name=? AND user_pwd=?`
	var userId string
	if err = r.db.Get(&userId, sqlStr, p.UserName, p.UserPwd); err != nil {
		if err == sql.ErrNoRows {
			err = errUserNotExists
			zaplog.L().Warn("invalid userName or pwd", zaplog.Fields(c, p, nil)...)
			resp.UnprovedParam(c, err.Error())
			return
		}
		zaplog.L().Error("query user by uname and pwd failed", zaplog.Fields(c, p, err)...)
		resp.ServerBusy(c)
		return
	}
	np = p
	np.UserId = userId
	return
}